module design_main #(
    parameter IMEM_InitEn   = 1,
    parameter IMEM_MEMFILE  = "imageI.txt",
    parameter DMEM_InitEn   = 1,
    parameter DMEM_MEMFILE  = "imageD.txt"

)
(
    input   logic           clk,
    input   logic           rst_n
);


localparam ADDR_RA = 'd31;


logic [7:0]     IMem_Addr;
logic [31:0]    IMem_Data;
logic [31:0]    Inst_code;
logic [31:0]    PC_new;
logic [31:0]    if_rs_Data;
logic [31:0]    if_offset;
logic [25:0]    if_address;

logic [5:0]     op_code;
logic [4:0]     rs_addr;
logic [4:0]     rt_addr;
logic [4:0]     rd_addr;
logic [4:0]     shamt;
logic [5:0]     func;
logic [15:0]    imm;
logic [25:0]    address;

logic [31:0]    imm32;

logic           Write_Reg;
logic           Mem_Write;
logic [2:0]     ALU_OP;
logic [1:0]     w_r_s;
logic           imm_s;
logic [1:0]     wr_data_s;
logic           rt_imm_s;
logic [1:0]     PC_s;

logic [4:0]     R_Addr_A;
logic [4:0]     R_Addr_B;
logic [4:0]     W_Addr;
logic [31:0]    W_Data;
logic [31:0]    R_Data_A;
logic [31:0]    R_Data_B;

logic [31:0]    alu_A;
logic [31:0]    alu_B;
logic [31:0]    alu_F;
logic           alu_ZF;
logic           alu_OF;
logic           alu_SF;
logic           alu_PF;
logic           alu_CF;

logic [7:0]     DMem_Addr;
logic [31:0]    DMem_wData;
logic [31:0]    DMem_rData;

assign if_rs_Data   = R_Data_A;
assign if_offset    = imm32;
assign if_address   = address;

assign R_Addr_A     = rs_addr;
assign R_Addr_B     = rt_addr;
assign W_Addr       = (w_r_s == 2'd0) ?rd_addr :
                      (w_r_s == 2'd1) ?rt_addr :
                      (w_r_s == 2'd2) ?ADDR_RA :'d0;
assign W_Data       = (wr_data_s == 2'd0) ?alu_F :
                      (wr_data_s == 2'd1) ?DMem_rData :
                      (wr_data_s == 2'd2) ?PC_new :'d0;

assign imm32        = (imm_s) ?{{16{imm[15]}}, imm} :{16'd0, imm};

assign alu_A        = R_Data_A;
assign alu_B        = (rt_imm_s) ?imm32 :R_Data_B;

assign DMem_Addr    = alu_F[7:0];
assign DMem_wData   = R_Data_B;

instFetch u_instFetch(
    .clk       (clk       ),
    .rst_n     (rst_n     ),
    .IMem_Addr (IMem_Addr ),
    .IMem_Data (IMem_Data ),
    .Inst_code (Inst_code ),
    .PC_new    (PC_new    ),
    .PC_s      (PC_s      ),
    .rs_Data   (if_rs_Data   ),
    .offset    (if_offset    ),
    .address   (if_address   )
);

memory #(
    .InitEn  (IMEM_InitEn  ),
    .MEMFILE (IMEM_MEMFILE )
)
u_IMem(
    .clk       (clk       ),
    .Mem_Addr  (IMem_Addr ),
    .Mem_Write (1'b0      ),
    .M_W_Data  (32'b0     ),
    .Mem_Read  (1'b1      ),
    .M_R_Data  (IMem_Data )
);

instDecoder u_instDecoder(
    .Inst_code (Inst_code ),
    .op_code   (op_code   ),
    .rs_addr   (rs_addr   ),
    .rt_addr   (rt_addr   ),
    .rd_addr   (rd_addr   ),
    .shamt     (shamt     ),
    .func      (func      ),
    .imm       (imm       ),
    .address   (address   )
);

exec u_exec(
    .op_code   (op_code   ),
    .func      (func      ),
    .zf        (alu_ZF    ),
    .Write_Reg (Write_Reg ),
    .Mem_Write (Mem_Write ),
    .ALU_OP    (ALU_OP    ),
    .w_r_s     (w_r_s     ),
    .imm_s     (imm_s     ),
    .wr_data_s (wr_data_s ),
    .rt_imm_s  (rt_imm_s  ),
    .PC_s      (PC_s      )
);


regBank u_regBank(
    .clk       (clk       ),
    .rst_n     (rst_n     ),
    .R_Addr_A  (R_Addr_A  ),
    .R_Addr_B  (R_Addr_B  ),
    .Write_Reg (Write_Reg ),
    .W_Addr    (W_Addr    ),
    .W_Data    (W_Data    ),
    .R_Data_A  (R_Data_A  ),
    .R_Data_B  (R_Data_B  )
);

ALU u_ALU(
    .clk    (clk    ),
    .rst_n  (rst_n  ),
    .ALU_OP (ALU_OP ),
    .A      (alu_A      ),
    .B      (alu_B      ),
    .F      (alu_F      ),
    .ZF     (alu_ZF     ),
    .OF     (alu_OF     ),
    .SF     (alu_SF     ),
    .PF     (alu_PF     ),
    .CF     (alu_CF     )
);

memory #(
    .InitEn  (DMEM_InitEn  ),
    .MEMFILE (DMEM_MEMFILE )
)
u_DMem(
    .clk       (clk        ),
    .Mem_Addr  (DMem_Addr  ),
    .Mem_Write (Mem_Write  ),
    .M_W_Data  (DMem_wData ),
    .Mem_Read  (1'b1       ),
    .M_R_Data  (DMem_rData )
);

// make verilator happy
logic [8:0] unused;
assign unused = {shamt, alu_OF, alu_SF, alu_PF, alu_CF};


endmodule
